package com.cruisecontrol4eclipse.core.model;

import java.io.IOException;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Set;

import javax.management.InstanceNotFoundException;
import javax.management.MBeanException;
import javax.management.MBeanServerConnection;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import javax.management.ReflectionException;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;

import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.ui.PlatformUI;

import com.cruisecontrol4eclipse.core.model.CruiseControlProject.Status;

public class CruiseControlServer {
	private static final String ALL_PROJECTS = "CruiseControl Project:*";
	private static final String PROJECT = "CruiseControl Project:name=";

	private static MBeanServerConnection createConnection(String host, int rmiPort) {
		JMXServiceURL jmxURL;
		System.setProperty("java.naming.factory.initial",
				"com.sun.jndi.rmi.registry.RegistryContextFactory");
		System.setProperty("java.naming.provider.url", "rmi://"+host+":"+rmiPort);
		try {
			jmxURL = new JMXServiceURL(("service:jmx:rmi://" + host + ":"
					+ rmiPort + "/jndi/jrmp"));
		} catch (MalformedURLException e) {
			throw new RuntimeException(e);
		}

		try {
			JMXConnector jmxc = JMXConnectorFactory.connect(jmxURL, new HashMap<String,Object>());
			return jmxc.getMBeanServerConnection();
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
	}

	public static List<CruiseControlProject> getCruiseControlProjects(String host,
			int rmiPort, int httpPort) {
		try {
			MBeanServerConnection connection = createConnection(host, rmiPort);
			Set<ObjectName> objectNames = connection.queryNames(
					new ObjectName(ALL_PROJECTS), null);
			List<CruiseControlProject> projects = new ArrayList<CruiseControlProject>(objectNames.size());
			for (ObjectName object : objectNames) {
				CruiseControlProject cruiseControlProject = new CruiseControlProject();
				new CruiseControlProjectSyncronizer(cruiseControlProject, connection , object, host, rmiPort, httpPort);
				projects.add(cruiseControlProject);
			}
			return projects;
		} catch (IOException e) {
		} catch (MalformedObjectNameException e) {
		}
		return Collections.emptyList();
	}
	
	public static void forceBuild(CruiseControlProject project, String host, int rmiPort) {
		if(Status.NOW_BUILDING.equals(project.getStatus())) {
			MessageDialog.openInformation(PlatformUI.getWorkbench().getDisplay().getActiveShell(), "Already building", "The project is already building.\n"+project.getName());
		} else if(Status.PAUSED.equals(project.getStatus())) {
			MessageDialog.openInformation(PlatformUI.getWorkbench().getDisplay().getActiveShell(), "Project is paused", "The project is paused, please resume it first.\n"+project.getName());
		} else {
			MBeanServerConnection connection = createConnection(host, rmiPort);
			try {
				ObjectName mbeanObj = ObjectName.getInstance(PROJECT+project.getName());
				connection.invoke(mbeanObj, "build", new Object[0], new String[0]);
				MessageDialog.openInformation(PlatformUI.getWorkbench().getDisplay().getActiveShell(), "Requested build", "A request was send to the server to build project.\n"+project.getName());
				return;
			} catch (Exception e) {
				MessageDialog.openError(PlatformUI.getWorkbench().getDisplay().getActiveShell(), "Error", "An error occured while sending the request to build the project.\n"+project.getName());
			}
		}
	}
	
	public static void pauseBuild(CruiseControlProject project, String host, int rmiPort) {
		if(Status.PAUSED.equals(project.getStatus())) {
			MessageDialog.openInformation(PlatformUI.getWorkbench().getDisplay().getActiveShell(), "Already paused", "The project is already paused.\n"+project.getName());
		} else {
			MBeanServerConnection connection = createConnection(host, rmiPort);
			try {
				ObjectName mbeanObj = ObjectName.getInstance(PROJECT+project.getName());
				connection.invoke(mbeanObj, "pause", new Object[0], new String[0]);
				//calling build to get it to update status to paused
				connection.invoke(mbeanObj, "build", new Object[0], new String[0]);
				MessageDialog.openInformation(PlatformUI.getWorkbench().getDisplay().getActiveShell(), "Requested pause build", "A request was send to the server to pause the build of project.\n"+project.getName());
				return;
			} catch (Exception e) {
				MessageDialog.openError(PlatformUI.getWorkbench().getDisplay().getActiveShell(), "Error", "An error occured while sending the request to pause the build of project.\n"+project.getName());
			}
		}
	}
	
	public static void resumeBuild(CruiseControlProject project, String host, int rmiPort) {
		if(!Status.PAUSED.equals(project.getStatus())) {
			MessageDialog.openInformation(PlatformUI.getWorkbench().getDisplay().getActiveShell(), "Project is not paused", "The project is not paused.\n"+project.getName());
		} else {
			MBeanServerConnection connection = createConnection(host, rmiPort);
			try {
				ObjectName mbeanObj = ObjectName.getInstance(PROJECT+project.getName());
				connection.invoke(mbeanObj, "resume", new Object[0], new String[0]);
				MessageDialog.openInformation(PlatformUI.getWorkbench().getDisplay().getActiveShell(), "Requested resume build", "A request was send to the server to resume the paused project.\n"+project.getName());
				return;
			} catch (Exception e) {
				MessageDialog.openError(PlatformUI.getWorkbench().getDisplay().getActiveShell(), "Error", "An error occured while sending the request to resume the project.\n"+project.getName());
			}
		}
	}
	
	public static void getBuildOutput(CruiseControlProject project, String host, int rmiPort) {
		MBeanServerConnection connection = createConnection(host, rmiPort);
		try {
			ObjectName mbeanObj = ObjectName.getInstance(PROJECT+project.getName());
			String[] buildOutput = (String[]) connection.invoke(mbeanObj, "getBuildOutput", new Object[] { new Integer(0)}, new String[] { Integer.class.getName()});
			
			String test = "";
			for (String string : buildOutput) {
				test = test+string+"\n";
			}
			MessageDialog.openInformation(PlatformUI.getWorkbench().getDisplay().getActiveShell(), "Requested build output", test);
			return;
		} catch (Exception e) {
			MessageDialog.openError(PlatformUI.getWorkbench().getDisplay().getActiveShell(), "Error", "An error occured while sending the request to get the build output for the project.\n"+project.getName());
		}
	}
}
